#include "FunTrace.h"
#include <http.h>
#include "publictransportsgquery.h"
#include <aknglobalnote.h> 
#include <aknnotewrappers.h> 

const TInt kPublicTransportTimeout = 45*1000000;


_LIT(kFormatRequestPending, "\trequesting...");
_LIT(kFormatRequestScheduled, "\tqueued, select to request");
_LIT(kFormatRequestScheduledWaitingConnection, "\tqueued, waiting connection");
_LIT(kFormatRequestWait, "\tselect to request");
_LIT(kFormatRequestSchedule, "\tevery %S");
_LIT(kFormatRequestCompleted, "\t%S \xf814 %S");
_LIT(kFormatRequestBlocked, "\tunexpected answer (probably blocked by SBS or SMRT), please check whether the app has been updated");
_LIT(kFormatRequestPendingCaptcha, "\trequesting captcha...");
_LIT(kFormatRequestDownloadingCaptcha, "\tdownloading captcha...");
_LIT(kFormatCaptchaError, "\tcaptcha processing error");
_LIT(kFormatRequestSubmittingCaptcha, "\tsubmitting captcha...");
_LIT(kFormatSolvingCaptcha, "\tsolving captcha...");
_LIT(kFormatRequestError, "\terror (%S, %S)");
_LIT(kFormatRequestUnavailable, "\tschedule unavailable");
_LIT(kFormatRequestPendingInitialization, "\twaiting for initialization...");
_LIT(kFormatRequestPendingToken, "\trequesting token...");
_LIT(kFormatRequestPendingCrowdToken, "\trequesting crowd token...");
_LIT(kFormatRequestSelectingBus, "\tselecting bus...");

static void PrintNoteL(TRefByValue<const TDesC> aFormat, ...)
    {
    VA_LIST list;
    VA_START(list, aFormat);
    TBuf<256> buf;
    buf.FormatList(aFormat, list);
    VA_END(list);
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL(EAknGlobalInformationNote, buf); 
    CleanupStack::PopAndDestroy(globalNote);
    }


CPublictransportsgSession::CPublictransportsgSession()
	{
	iPublicTransportTimeoutTimer.CreateLocal();
	iPublicTransportTimeoutTimerHelper = NULL;
	}

CPublictransportsgSession* CPublictransportsgSession::NewL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
CPublictransportsgSession* self = CPublictransportsgSession::NewLC();
	CleanupStack::Pop( self );
	return self;
	}

CPublictransportsgSession* CPublictransportsgSession::NewLC()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
CPublictransportsgSession* self = new ( ELeave ) CPublictransportsgSession();
	CleanupStack::PushL( self );
	self->ConstructL();
	return self;
	}
void CPublictransportsgSession::ConstructL()
{
	iPublicTransportTimeoutTimerHelper = CActiveHelper<RTimer*>::NewL();	
}

void CPublictransportsgSession::SetConnectionInfo(const RConnection& aConnection, const RSocketServ& aSocketServ)
	{
	iHTTPSession.OpenL();
	RStringPool strP = iHTTPSession.StringPool();
	RHTTPConnectionInfo connInfo = iHTTPSession.ConnectionInfo();
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable() ), THTTPHdrVal (aSocketServ.Handle()) );
	TInt connPtr = REINTERPRET_CAST(TInt, &aConnection);
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable() ), THTTPHdrVal (connPtr) );
	}

CPublictransportsgSession::~CPublictransportsgSession()
	{
	delete iPublicTransportTimeoutTimerHelper;
	iPublicTransportTimeoutTimer.Close();
	iHTTPSession.Close();
	}



void CPublictransportsgSession::MActiveHelperCallbackRunL(CActiveHelper<RTimer*>* aActiveHelper, RTimer* aTimer)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);

if(aActiveHelper->iStatus != KErrNone) return;

		{
		for(TInt i = 0 ; i < iPublictransportsgQueries.Count() ; ++i)
			if(iPublictransportsgQueries[i]->iRequestStatus == CPublictransportsgQuery::ERequestPending)
				{
				iPublictransportsgQueries[i]->Cancel();
				iPublictransportsgQueries[i]->SubmitL();
				}
		}
}

TInt CPublictransportsgSession::MActiveHelperCallbackRunError(CActiveHelper<RTimer*>* aActiveHelper, RTimer* aTimer, TInt aError)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
}

void CPublictransportsgSession::MActiveHelperCallbackDoCancel(CActiveHelper<RTimer*>* aActiveHelper, RTimer* aTimer)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	aTimer->Cancel();
}

// ================
// ================
// ================
void CPublictransportsgQuery::ConstructL()
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iStop = NULL;
	iBody.CreateL(4096);
}

CPublictransportsgQuery* CPublictransportsgQuery::NewLC()
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CPublictransportsgQuery* ret = new (ELeave) CPublictransportsgQuery;
	CleanupStack::PushL(ret);
	ret->ConstructL();
	return ret;
}

CPublictransportsgQuery* CPublictransportsgQuery::NewL()
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CPublictransportsgQuery* ret = NewLC();
	CleanupStack::Pop(ret);
	return ret;
}

void CPublictransportsgQuery::SubmitL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	RBuf8 uristr;
	CleanupClosePushL(uristr);
	uristr.CreateL(1024);
	uristr.AppendFormat(_L8("http://www.publictransport.sg/publish/mobile/en/busarrivaltime.jsp?submit=submit&bus_stop=%S"), iStop);
	TUriParser8 uri;
	uri.Parse( uristr );
	RStringF method = iSession->iHTTPSession.StringPool().StringF(HTTP::EGET,RHTTPSession::GetTable());
	CleanupClosePushL(method);
	iTransaction.Close();
	iTransaction = iSession->iHTTPSession.OpenTransactionL(uri, *this, method);

	{
		// server does not support pipelining
		RStringPool strP = iSession->iHTTPSession.StringPool();
		const TStringTable& stringTable = RHTTPSession::GetTable();
		RStringF httpPipelining = strP.StringF( HTTP::EHttpPipelining, stringTable );
		THTTPHdrVal disablePipelining = strP.StringF( HTTP::EDisablePipelining, stringTable );
		iTransaction.PropertySet().RemoveProperty( httpPipelining );
		iTransaction.PropertySet().SetPropertyL( httpPipelining, disablePipelining );
	}
	
	iBody.Zero();
	iLastError = KErrNone;
	iSession->iPublicTransportTimeoutTimerHelper->Cancel();
	iSession->iPublicTransportTimeoutTimer.After(iSession->iPublicTransportTimeoutTimerHelper->iStatus, kPublicTransportTimeout);
	iSession->iPublicTransportTimeoutTimerHelper->SetActive(iSession, &iSession->iPublicTransportTimeoutTimer);		
	iTransaction.SubmitL();
	iCallbacksCompleted = EFalse;
	CleanupStack::PopAndDestroy(&method);
	CleanupStack::PopAndDestroy(&uristr);
	}

TBool CPublictransportsgQuery::Pending() const
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	return (iTransaction != RHTTPTransaction()) || !iCallbacksCompleted;
	}

void CPublictransportsgQuery::Cancel()
	{
	if(iTransaction != RHTTPTransaction())
		{
		iTransaction.Cancel();
		iTransaction.Close();
		iTransaction = RHTTPTransaction();
		}
	}

CPublictransportsgQuery::~CPublictransportsgQuery()
{
	delete iStop;
	iTransaction.Close();
	iBody.Close();
}

static TInt Locate2(const TDesC8& aDesC, TChar aChar1, TChar aChar2)
	{
	TInt ret;
	for(ret = 0 ; ret < aDesC.Length() && !(aDesC[ret] == aChar1 || aDesC[ret] == aChar2) ; ++ret);
	if(ret == aDesC.Length()) ret = KErrNotFound;
	return ret;
	}



void CPublictransportsgQuery::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
if(aEvent.iStatus < KErrNone) iLastError = aEvent.iStatus;
	  switch (aEvent.iStatus)
	    {
			case THTTPEvent::EUnrecoverableError:
				iLastError = KErrNotReady; // for Symbian 5th ed + 
			  break;
	    case THTTPEvent::EGotResponseHeaders:
	      break;

	    case THTTPEvent::EGotResponseBodyData:
	    	{
		      MHTTPDataSupplier* body = aTransaction.Response().Body();
		      TPtrC8 part;	      
		      body->GetNextDataPart(part);
		      if(part.Length() + iBody.Length() > iBody.MaxLength() )
		    	  iBody.ReAllocL(part.Length() + iBody.Length());	    	  	    	  
	    	  iBody.Append(part);	    	  	    	  
		      body->ReleaseData();
	    	}		      
	      break;

	    case THTTPEvent::ESucceeded:
	    case THTTPEvent::EFailed:
	    	TInt statusCode = aTransaction.Response().StatusCode();
			iSession->iPublicTransportTimeoutTimerHelper->Cancel();
			iSession->iPublicTransportTimeoutTimer.After(iSession->iPublicTransportTimeoutTimerHelper->iStatus, kPublicTransportTimeout);
			iSession->iPublicTransportTimeoutTimerHelper->SetActive(iSession, &iSession->iPublicTransportTimeoutTimer);		
	    	Cancel();
			
			HBufC8* savStop = iStop;
			iStop = NULL;
			struct{ } iStop, iService; // to "remove" the variables from the scope
			CleanupStack::PushL(savStop);
			
			if(aEvent.iStatus == THTTPEvent::ESucceeded)
				{
		    	_LIT8(kPrefix, "<td align=\"left\">");

		    	TPtrC8 svcrow = iBody;
		    	TInt begsvcrow, nextsvcrow;
		    	TInt svcrowindex = 0;
		    	for(begsvcrow = svcrow.Find(kPrefix), svcrowindex = 0 ; begsvcrow != KErrNotFound ; begsvcrow = nextsvcrow, ++svcrowindex)
		    		{
					svcrow.Set( svcrow.Mid(begsvcrow) );
					TPtrC8 field[3];
					TInt begtd = 0, nexttd;
					for(TInt i = 0 ; i < 3 ; ++i, begtd = nexttd)
						{
						const TInt begfield = begtd + 1 + User::LeaveIfError( svcrow.Mid(begtd).Locate('>') );
			    		const TInt endfield = begfield + User::LeaveIfError( Locate2(svcrow.Mid(begfield), '<', '&') );
			    		const TInt nexttd_endfield = svcrow.Mid(endfield).Find(kPrefix);
			    		nexttd = (nexttd_endfield != KErrNotFound) ? endfield + nexttd_endfield : KErrNotFound;
			    		field[i].Set( svcrow.Mid(begfield, endfield - begfield) );
			    		}
					nextsvcrow = nexttd;				
					(*iCallback.Get())(this, (*savStop), (*&field[0]), CPublictransportsgQuery::ERequestCompleted, (*&kFormatRequestCompleted()), (*&field[1]), (*&field[2]));
					}
				}
			else
				{
				(*iCallback.Get())(this, (*savStop), (*&KNullDesC8()), CPublictransportsgQuery::ERequestError, (*&kFormatRequestError()), (*&KNullDesC8()), (*&KNullDesC8()));
				}
			
			iCallbacksCompleted = ETrue;
			CleanupStack::PopAndDestroy(savStop);			
			
	      break;

	    case THTTPEvent::ERedirectedPermanently:
	      break;
	    	
	    case THTTPEvent::ERedirectedTemporarily:
	      break;
	    	
	    default:
	      break;
	    }
	}
TInt CPublictransportsgQuery::MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	}



